Setting up CI CD for Developers
This tutorial will guide you through the steps to set up a project on the ABAIR CI/CD pipeline. As an example, it uses a node application with the name ABAIR_APP_X.
Prerequisites:
-
Server:
- You have a key for your project to SSH into the services VM.
- An Admin has set up a directory for your project with a deployment script.
-
Github:
- You are a member of the Phonetics & Speech Lab Github Organisation.
- You have created a remote Git repository on Github for
ABAIR_APP_X - You have initialised a local Git repository and linked it to the remote.
-
Docker:
- You have Docker installed on your local machine.
- You have a Dockerfile in the root of your project that successfully builds an image of your application.
- This image can be run locally using Docker and accessed over the specified open port.
- You have been given the Docker Password for the registry.
Steps
1. Add CI/CD Github Actions to your project
Create a .github/workflows/ folder in the root of your project and add the following 2 files
ci.yml
name: Node.js CI
on:
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js LTS
uses: actions/setup-node@v3
with:
node-version: 18.16.0
- run: |
npm i
cd.yml
name: Publish Docker image
on:
push:
branches:
- main
jobs:
push_to_registry:
name: Push Docker image to Docker Registry
runs-on: ubuntu-latest
environment: prod
steps:
- name: Check out the repo
uses: actions/checkout@v2
- name: Log in to Docker Hub
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ${{ vars.DOCKER_REGISTRY }}
username: ${{ vars.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: registry.abair.ie:5000/${{ vars.PROJECT_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
update_ssh:
name: Update running software
needs: "push_to_registry"
runs-on: ubuntu-latest
environment: prod
steps:
- name: executing remote ssh commands using password
uses: appleboy/ssh-action@master
with:
host: ${{ vars.HOST }}
username: ${{ vars.USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ vars.PORT }}
script: bash ${{ vars.DEPLOY_SCRIPT_PATH }}
2. Generate SSH Private Key
Recommended: Use the generate-ssh-key.sh script which automates the steps below.
- Sign into the Services VM as a sudo user.
- Sign into the services account using
sudo su services. - Run the following command to generate the SSH key. Make sure to replace ABAIR_APP_X with the name of your app.
ssh-keygen -t ed25519 -a 100 \
-C "ABAIR_APP_X Github Action" \
-f ~/.ssh/ABAIR_APP_X_ed25519 \
-N ""
- Add the public key to
authorized_keysso the Services VM accepts connections using this key:
cat ~/.ssh/ABAIR_APP_X_ed25519.pub >> ~/.ssh/authorized_keys
- Copy the private key contents to the GitHub
prodenvironment secrets asSSH_PRIVATE_KEY:
cat ~/.ssh/ABAIR_APP_X_ed25519
Copy the entire output (including -----BEGIN OPENSSH PRIVATE KEY----- and -----END OPENSSH PRIVATE KEY-----).
3. Create Environment and Set Secrets/Variables
On the Github page for ABAIR_APP_X:
3.1 Create the prod Environment
- Navigate to
Settings→Environments - Click
New environment - Name it
prodand clickConfigure environment
3.2 Add Environment Secrets
In the prod environment settings, under Environment secrets, add:
| Name | Value |
|---|---|
| DOCKER_PASSWORD | (provided by Admin) |
| SSH_PRIVATE_KEY | Private SSH key from the services user in the Services VM |
If your project uses external services, add their credentials as secrets too. Common examples:
| Name | Description |
|---|---|
| SUPABASE_SECRET_KEY | Supabase service role key (bypasses RLS) |
| ABAIR_APP_SMTP_PASSWORD | SMTP password for sending emails |
| UNSUBSCRIBE_SECRET | HMAC signing secret for secure tokens |
3.3 Add Environment Variables
In the prod environment settings, under Environment variables, add:
| Name | Value |
|---|---|
| PROJECT_NAME | ABAIR_APP_X |
| DOCKER_REGISTRY | registry.abair.ie:5000 |
| DOCKER_USERNAME | admin |
| HOST | srv.abair.ie |
| USERNAME | services |
| PORT | 22102 |
| DEPLOY_SCRIPT_PATH | /home/services/ABAIR_APP_X/deploy-ABAIR_APP_X.sh |
If your project needs environment variables at build time (e.g. Supabase, API URLs), add them as variables too:
| Name | Description |
|---|---|
| NEXT_PUBLIC_SUPABASE_URL | Supabase project URL |
| NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | Supabase anonymous/public key |
| NEXT_PUBLIC_APP_URL | Public URL of your application |
3.4 Pass Environment Variables in Workflows
CI: Add an env block to the build step so NEXT_PUBLIC_* variables are available during npm run build:
- name: Build application
run: npm run build
env:
NEXT_PUBLIC_SUPABASE_URL: ${{ vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${{ vars.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY }}
CD: Add a build-args block to the Docker build step. Use vars.* for non-sensitive values and secrets.* for credentials:
build-args: |
NEXT_PUBLIC_SUPABASE_URL=${{ vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=${{ vars.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY }}
SUPABASE_SECRET_KEY=${{ secrets.SUPABASE_SECRET_KEY }}
Your Dockerfile must declare matching ARG lines before RUN npm run build for these to take effect:
ARG NEXT_PUBLIC_SUPABASE_URL
ARG NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
ARG SUPABASE_SECRET_KEY
Note:
NEXT_PUBLIC_*variables are inlined by Next.js at build time into the client bundle. Server-only secrets (without theNEXT_PUBLIC_prefix) are only available server-side and should be provided as runtime environment variables or DockerENVin the production stage of your Dockerfile.
4. Deploy Script
Add the following deploy script to the base of your project for reference. It will be copied by Admin to the Services VM
deploy-ABAIR_APP_X.sh
docker stop ABAIR_APP_X
docker rm ABAIR_APP_X
docker login 10.0.0.2:5000 -u admin -p {see elsewhere}
docker rmi 10.0.0.2:5000/ABAIR_APP_X:main
docker pull 10.0.0.2:5000/ABAIR_APP_X:main
docker run -t -d -p port:port --restart always --name project-name 10.0.0.2:5000/ABAIR_APP_X:main
FAQ
The CI/CD Fails when I add Supabase to my project
This usually means NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY are not available at build time. Follow Section 3.4 to add the required variables and build-args to your workflows and Dockerfile.
Failing to authorize using publickey
Follow this carefully.
- Make sure your private SSH key is pasted correctly into the GitHub
prodenvironment secrets asSSH_PRIVATE_KEY. You must copy all contents of the file. - Make sure that your ssh key file is named correctly (ABAIR_APP_X_ed25519).
- Make sure that your public ssh key is added to authorized keys.